# -*- coding: binary -*-

require 'rspec'

RSpec.describe Msf::Exploit::Remote::SMB::Client::KerberosAuthentication do
  let(:mock_authenticator) do
    instance_double(Msf::Exploit::Remote::Kerberos::ServiceAuthenticator::SMB)
  end

  let(:smb1) { true }
  let(:smb2) { true }
  let(:smb3) { true }

  subject do
    mock_dispatcher = instance_double(RubySMB::Dispatcher::Base, is_a?: true)
    allow(mock_dispatcher).to receive(:is_a?).with(RubySMB::Dispatcher::Base).and_return(true)

    smb_client = ::RubySMB::Client.new(
      mock_dispatcher,
      username: '',
      password: '',
      smb1: smb1,
      smb2: smb2,
      smb3: smb3
    )
    smb_client.extend(Msf::Exploit::Remote::SMB::Client::KerberosAuthentication)
    smb_client.kerberos_authenticator = mock_authenticator
    smb_client
  end

  before(:each) do
    allow(subject).to receive(:negotiation_security_buffer).and_return(negotiation_security_buffer)
  end

  context 'when kerberos is not supported' do
    let(:negotiation_security_buffer) do
      "\x60\x28\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x1e\x30\x1c\xa0\x1a" \
      "\x30\x18\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e\x06\x0a" \
      "\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a"
    end

    let(:smb1) { true }

    describe '#authenticate' do
      it 'raises an error' do
        expect { subject.authenticate }.to raise_error ::RubySMB::Error::AuthenticationFailure, /Unable to negotiate kerberos/
      end
    end
  end

  context 'when Kerberos is supported' do
    let(:negotiation_security_buffer) do
      "\x60\x76\x06\x06\x2b\x06\x01\x05\x05\x02\xa0\x6c\x30\x6a\xa0\x3c" \
      "\x30\x3a\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x1e\x06\x09" \
      "\x2a\x86\x48\x82\xf7\x12\x01\x02\x02\x06\x09\x2a\x86\x48\x86\xf7" \
      "\x12\x01\x02\x02\x06\x0a\x2a\x86\x48\x86\xf7\x12\x01\x02\x02\x03" \
      "\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a\xa3\x2a\x30\x28" \
      "\xa0\x26\x1b\x24\x6e\x6f\x74\x5f\x64\x65\x66\x69\x6e\x65\x64\x5f" \
      "\x69\x6e\x5f\x52\x46\x43\x34\x31\x37\x38\x40\x70\x6c\x65\x61\x73" \
      "\x65\x5f\x69\x67\x6e\x6f\x72\x65"
    end

    describe '#authenticate' do
      context 'when smb1' do
        let(:smb1) { true }
        let(:smb2) { false }
        let(:smb3) { false }

        describe '#authenticate' do
          before(:each) do
            allow(subject).to receive(:smb1_authenticate)
            subject.authenticate
          end

          it 'calls smb1_authenticate' do
            expect(subject).to have_received(:smb1_authenticate)
          end
        end
      end

      context 'when smb2' do
        let(:smb1) { false }
        let(:smb2) { true }
        let(:smb3) { false }

        describe '#authenticate' do
          before(:each) do
            allow(subject).to receive(:smb2_authenticate)
            subject.authenticate
          end

          it 'calls smb2_authenticate' do
            expect(subject).to have_received(:smb2_authenticate)
          end
        end
      end
    end
  end
end
